package entity

import (
	"sync"
	"sync/atomic"
	"time"

	"src/zeus/msghandler"
	. "src/zeus/msghandler"

	"src/gcommon"
	"src/protoMsg"
	"src/zeus/bytestream"
	"src/zeus/common"
	"src/zeus/dbservice"
	"src/zeus/iserver"
	"src/zeus/logger"
	"src/zeus/msgdef"
)

type IEntityReal interface {
	iserver.IEntity
	iEntityState

	//后代可以重载的方法

	//同步到客户端和别的服务器
	ReflushSync()
	// ReflushFromMsg 从消息中更新属性
	ReflushFromMsg(num int, data []byte)
	//
	ReflushPropFromMsg(bs *bytestream.ByteStream) (index uint16, err error)

	// 打包自己关心的脏属性
	PackMRoleDirtyProps() (result *protoMsg.PropBaseSyncList)
	// //同步到DB
	// ReflushToDB()
	// //从DB加载
	// ReflushFromDB()
}

// iEntityState Entity的状态相关函数
type iEntityState interface {
	OnInit()
	OnAfterInit()
	OnLoop()
	OnDestroy()
	IsDestroyed() bool
}

// iEntityState 留给后代作一些回调方法
type iEntityInit interface {
	Init(interface{})
}

type iEntityLoop interface {
	Loop()
}

type iEntityDestroy interface {
	Destroy()
}

type iEntityInitFinish interface {
	InitFinish()
}

// delayedSendMsg 需要延迟发送的消息结构
type delayedSendMsg struct {
	srvType uint8
	msg     msgdef.IMsg
}

// Entity 代表服务器端一个可通讯对象
type Entity struct {
	*MsgHandler
	*PropsSyncContainer
	entityType   string
	groups       sync.Map
	entityID     uint64
	dbid         uint64
	spaceID      uint64
	spaceSrvType uint8

	flyEntity bool
	initParam interface{}

	state   uint32
	nowTime time.Time
	// ntt对象的tick尝试使用server的time.now这样全局只需要拿一次time.now就可以完成一次所有对应的tick
	ticker chan time.Time

	srvIDS []*dbservice.EntitySrvInfo
	//用户身上涉及到的锁
	Mux *sync.RWMutex

	clientSess iserver.ISess //Entity 绑定的会话

	isDebug bool

	realPtr     IEntityReal
	entitiesPtr iserver.IEntities
	ieState     iEntityState

	destroySignal chan bool
	isDirectMode  atomic.Bool // 直连模式, ServerTypeClient类型不经过转发
	onDestroyFunc func()
	isFailLoad    bool //是否加载失败，如果失败，后面的逻辑就不继续下去了
}

// 是否加载失败，如果失败，后面的逻辑就不继续下去了
func (this *Entity) GetIsFailLoad() bool {
	return this.isFailLoad
}

// 是否加载失败，如果失败，后面的逻辑就不继续下去了
func (this *Entity) SetLoadFail() {
	this.isFailLoad = true
}

func (e *Entity) SetNetDirectMode(v bool) {
	e.isDirectMode.Store(v)
}

// SetClient 设置客户端的连接
func (e *Entity) SetClient(s iserver.ISess) {
	e.Mux.Lock()
	defer e.Mux.Unlock()
	e.clientSess = s
	if s == nil {
		return
	}
	e.isDirectMode.Store(true)
	e.clientSess.SetMsgHandler(e.MsgHandler)
}

func (e *Entity) GetRawClientSess() iserver.ISess {
	e.Mux.RLock()
	defer e.Mux.RUnlock()
	if e.clientSess != nil {
		return e.clientSess
	}
	return nil
}

// GetClientSess 获取客户端连接
func (e *Entity) GetClientSess() iserver.ISess {
	e.Mux.RLock()
	defer e.Mux.RUnlock()
	if e.clientSess != nil && !e.clientSess.IsClosed() {
		return e.clientSess
	}

	return nil
}

// GetDBID 获取实体的DBID
func (e *Entity) GetDBID() uint64 {
	return e.dbid
}

// GetID 获取实体ID
func (e *Entity) GetID() uint64 {
	return e.entityID
}

// GetType 获取实体类型
func (e *Entity) GetType() string {
	return e.entityType
}

// SetType 设置实体类型
func (e *Entity) SetType(t string) {
	e.entityType = t
}

// GetType 添加分组
func (e *Entity) AddGroup(g string) {
	e.groups.Store(g, g)
}

// GetType 添加分组
func (e *Entity) DelGroup(g string) {
	e.groups.Delete(g)
}

// GetType 获取分组列表
func (e *Entity) GetGroups() interface{} {
	return &e.groups
}

// GetType 获取分组
func (e *Entity) GetGroup(g string) (interface{}, bool) {
	return e.groups.Load(g)
}

// GetRealPtr 获取真实的后代对象的指针
func (e *Entity) GetRealPtr() interface{} {
	return e.realPtr
}

// GetInitParam 获取初始化参数
func (e *Entity) GetInitParam() interface{} {
	return e.initParam
}

// GetEntityState 获取当前状态
func (e *Entity) GetEntityState() uint32 {
	return atomic.LoadUint32(&e.state)
}

func (e *Entity) SetEntityState(st uint32) {
	atomic.StoreUint32(&e.state, st)
}

// GetEntities 获取包含自己的Entities指针
func (e *Entity) GetEntities() iserver.IEntities {
	return e.entitiesPtr
}

// GetProxy 获取实体的代理对象
func (e *Entity) GetProxy() iserver.IEntityProxy {
	return NewEntityProxy(iserver.GetSrvInst().GetSrvID(), e.GetSpaceID(), e.entityID)
}

func (e *Entity) GetNowTime() time.Time {
	return e.nowTime
}

func (e *Entity) SetNowTime(n time.Time) {
	e.nowTime = n
}

// 设置TICK的时间 只有系统协程可以对子协程做
func (e *Entity) SetTickerNow(n time.Time) {
	select {
	case e.ticker <- n:
	default:
	}
}

// 获取TICK器
func (e *Entity) GetTicker() <-chan time.Time {
	return e.ticker
}

// OnEntityCreated 初始化
func (e *Entity) OnEntityCreated(entityID uint64, entityType string, dbid uint64, spaceID uint64, protoType IEntityReal, entities iserver.IEntities, initParam interface{}, syncInit bool, fly bool) {
	e.ticker = make(chan time.Time, 1)
	// logger.Debug(logger.LogKey_LoginFlow, "[Entity] OnEntityCreated 登录流程 entityID: ", entityID, " entityType: ", entityType, "dbid: ", dbid)
	e.MsgHandler = msghandler.NewMsgHandler()
	e.PropsSyncContainer = NewPropsSyncContainer()
	// e.IPropsContainer = NewPropsContainer()
	// e.IPropsContainer.AddDirtyPropSorter(EDPSorterTypeSync).AddDirtyPropSorter(EDPSorterTypeSave)

	e.entityType = entityType
	// e.groups = &sync.Map{}
	e.entityID = entityID
	e.dbid = dbid
	e.spaceID = spaceID
	e.initParam = initParam
	e.flyEntity = fly

	e.realPtr = protoType
	e.entitiesPtr = entities

	e.SetEntityState(iserver.Entity_State_Init)
	e.ieState = protoType

	e.srvIDS = make([]*dbservice.EntitySrvInfo, 0, 8)
	e.Mux = &sync.RWMutex{}

	if ps, ok := e.realPtr.(iserver.IEntityPropsSetter); ok {
		ps.SetPropsSetter(e.realPtr.(iserver.IEntityProps))
	}
	if ec, ok := e.realPtr.(iEntityCtrl); ok {
		ec.OnPostEntityCreated()
	}
	if syncInit {
		ies := e.ieState
		ies.OnInit()
		ies.OnAfterInit()
	}
}

// OnEntityDestroyed 当Entity销毁时调用
func (e *Entity) OnEntityDestroyed() {
	state := e.GetEntityState()
	switch state {
	case iserver.Entity_State_Loop,
		iserver.Entity_State_Init,
		iserver.Entity_State_Suspend:
		e.SetEntityState(iserver.Entity_State_Destroy)
	}
	// if state == iserver.Entity_State_Loop || state == iserver.Entity_State_Init {
	// 	e.SetEntityState(iserver.Entity_State_Destroy)
	// }
	if e.onDestroyFunc != nil {
		e.onDestroyFunc()
	}
}

// IsDestroyed 是否删除
func (e *Entity) IsDestroyed() bool {
	return e.GetEntityState() == iserver.Entity_State_InValid
}
func (e *Entity) SetOnDestroyCallback(f func()) {
	e.onDestroyFunc = f
}

// MainLoop 主循环
func (e *Entity) MainLoop() {

	defer func() {
		if iserver.GetSrvInst().GetRecover() {
			if err := recover(); err != nil {
				logger.Error("Entity MainLoop panic :", err)
				buf := common.StackTrace()
				common.UpPanic(common.NewPanicSrvMD(
					int(iserver.GetSrvInst().GetGroupId()),
					int(iserver.GetSrvInst().GetSrvType()),
					int(iserver.GetSrvInst().GetCurSrvInfo().ServerID),
					"",
					err,
					e.realPtr, buf,
				))
				if iep, ok := e.realPtr.(iserver.IEntityPanic); ok {
					iep.OnPanic(common.GetError(err))
				}
			}
		}
	}()

	ies := e.ieState
	state := e.GetEntityState()
	switch state {
	case iserver.Entity_State_Init:
		{
			// if ec, ok := e.realPtr.(iEntityCtrl); ok {
			// 	ec.OnPostEntityCreated()
			// }
			ies.OnInit()
			ies.OnAfterInit()
		}
	case iserver.Entity_State_Loop:
		{
			ies.OnLoop()
		}
	case iserver.Entity_State_Destroy:
		{
			ies.OnDestroy()
			e.SetEntityState(iserver.Entity_State_InValid)
		}
	case iserver.Entity_State_SetRecycle:
		{
			//会进入这个状态的一定是副本场景，或是可以进入回收状态的东西
			if sp, ok := ies.(IRecycle); ok {
				sp.PutSpace()
			}
		}
	default:
		{
			// do nothing
		}
	}
	idh, ok := e.GetRealPtr().(iserver.IDelayCallHost)
	if ok {
		idh.GetDelayCallHandle().CallDelayExec()
	}
}

func (e *Entity) GetDestroySigChan() <-chan bool {
	if e.destroySignal == nil {
		e.destroySignal = make(chan bool, 1)
	}
	return e.destroySignal
}

// OnInit 初始化
func (e *Entity) GetPropDef(entityType string) *Def {
	return GetDefs().GetDef(e.entityType)
}
func (e *Entity) OnInit() {
	e.SetEntityState(iserver.Entity_State_Loop)
	if ic, ok := e.GetRealPtr().(IPropDefProvider); ok {
		e.InitProp(ic.GetPropDef(e.entityType), iserver.GetSrvInst().GetSaveType(), e.entityType)
	} else {
		logger.Warn("Entity 没有提供 IPropDefProvider 实现")
	}

	e.RegMsgProc(e.GetRealPtr())
	// e.IMsgHandlers.RegMsgProc(&Entity_MsgProc{e.realPtr})

	if !e.flyEntity {
		e.regSrvID()
	}
}

// OnAfterInit 后代的初始化
func (e *Entity) OnAfterInit() {
	ii, ok := e.GetRealPtr().(iEntityInit)
	if ok {
		ii.Init(e.GetInitParam())
		if iep, ok := e.GetRealPtr().(iserver.IEntityPanic); ok {
			e.MsgHandler.RegOnPanicFunc(iep.OnPanic)
		}
	} else {
		logger.Error("the entity ", e.GetType(), " no init method")
	}
}

// OnPanic 宕机 上层决定宕机时要做什么处理
func (e *Entity) OnPanic(err error) {
	gcommon.TickUserNtf(e, err)
	if e.clientSess != nil {
		e.clientSess.Close()
		e.clientSess = nil
	}
	// 如果在处理过程中，还有crash，那就直接return，不做其他处理
	if e.GetEntityState() == iserver.Entity_State_Destroy && e.GetEntityState() == iserver.Entity_State_InValid {
		return
	}
	logger.Warnf("the entity OnPanic %s", e.realPtr)
}

// OnDestroy 销毁
// 这个函数可以上层重载，上层的重载，需要调用基础的OnDestroy函数，来完成整体逻辑完整。
func (e *Entity) OnDestroy() {

	if id, ok := e.GetRealPtr().(iEntityDestroy); ok {
		id.Destroy()
	}

	if !e.flyEntity {
		e.unregSrvID()
	}
	/*
		因为销毁的时候，有可能还有脏数据
		这里原来只是做DB的保存，但其实还需要把一些同步到别的服务器上；
		因为有些服务器不负责做保存，需要同步到别的服务器上；
		由别的服务器进行保存；
	*/
	e.realPtr.ReflushSync()
	e.FlushDelayedMsgs()

	if e.clientSess != nil {
		e.clientSess.Close()
	}

	e.DestroyProp()
	//在MainLoop里会调用，所以这里就去掉了。
	// e.SetEntityState(iserver.Entity_State_InValid)
	//仅此处可处理销毁信号
	if e.destroySignal != nil {
		e.destroySignal <- true
		close(e.destroySignal)
		e.destroySignal = nil
	}
}

// OnLoop 运行时
func (e *Entity) OnLoop() {
	// 每帧处理顺序:
	// 处理消息和业务逻辑, 在业务逻辑中更改属性, 发送RPC消息, 此时仅缓存需要发送的RPC消息
	// 同步属性变化消息
	// 真正发送RPC消息

	e.DoMsg()
	e.DoLooper()
	e.realPtr.ReflushSync()
	// e.FlushDelayedMsgs()
}

// DoLooper 调用后代类的loop函数
func (e *Entity) DoLooper() {
	if ie, ok := e.GetRealPtr().(iEntityLoop); ok {
		ie.Loop()
	}
}
func (e *Entity) OnPostEntityCreated() {

}
